# src/runtime_map.py
import os, re
from typing import Iterable, List, Dict, Set, Optional

# ===== 构建期：pkg-config -> RPM =====
BUILD_PKGCFG_TO_RPM = {
    "opencv4": ["opencv-devel", "opencv"],
    "libpng": ["libpng-devel"],
    "libjpeg": ["libjpeg-turbo-devel"],
    "libtiff-4": ["libtiff-devel"],
    "libwebp": ["libwebp-devel"],
    "freetype2": ["freetype-devel"],
    "harfbuzz": ["harfbuzz-devel"],
    "zlib": ["zlib-devel"],
    "bzip2": ["bzip2-devel"],
    "liblzma": ["xz-devel"],
    "libcurl": ["libcurl-devel"],
    "libxml-2.0": ["libxml2-devel"],
    "libxslt": ["libxslt-devel"],
    "sqlite3": ["sqlite-devel"],
    "libavcodec": ["ffmpeg-devel"],
    "libavformat": ["ffmpeg-devel"],
    "libavutil": ["ffmpeg-devel"],
    "libswscale": ["ffmpeg-devel"],
    "libpostproc": ["ffmpeg-devel"],
    "libswresample": ["ffmpeg-devel"],
}
def map_pkgmods_to_build_rpms(pkgmods: List[str] | Set[str]) -> List[str]:
    pkgs, seen = [], set()
    for mod in pkgmods or []:
        for rpm in BUILD_PKGCFG_TO_RPM.get(mod, []):
            if rpm not in seen:
                seen.add(rpm); pkgs.append(rpm)
    return pkgs

# ===== 构建期：cgo -lxxx -> devel =====
CGO_LIB_TO_RPM = {
    "ssl": "openssl-devel", "crypto": "openssl-devel",
    "z": "zlib-devel", "bz2": "bzip2-devel", "lzma": "xz-devel",
    "curl": "libcurl-devel", "xml2": "libxml2-devel", "xslt": "libxslt-devel",
    "pcre2": "pcre2-devel", "ffi": "libffi-devel", "sqlite3": "sqlite-devel",
    "m": "glibc-devel", "pthread": "glibc-devel", "dl": "glibc-devel", "rt": "glibc-devel",
    "stdc++": "libstdc++-devel",
}
def map_cgolibs_to_build_rpms(cgo_libs: List[str] | Set[str]) -> List[str]:
    return sorted({CGO_LIB_TO_RPM[lib] for lib in (cgo_libs or []) if lib in CGO_LIB_TO_RPM})

# ===== 运行期 =====
SO_LIB_TO_RPM = {
    "libssl.so": "openssl-libs", "libcrypto.so": "openssl-libs",
    "libz.so": "zlib", "libbz2.so": "bzip2", "liblzma.so": "xz",
    "libcurl.so": "libcurl", "libxml2.so": "libxml2", "libxslt.so": "libxslt",
    "libpcre2.so": "pcre2", "libffi.so": "libffi", "libsqlite3.so": "sqlite",
    "libstdc++.so": "libstdc++", "libuuid.so": "libuuid", "libnghttp2.so": "nghttp2",
    "libidn2.so": "libidn2",
}
PATH_HINTS_TO_RPM = {
    "/etc/ssl/certs": "ca-certificates",
    "/etc/pki/ca-trust": "ca-certificates",
    "/usr/share/zoneinfo": "tzdata",
}
def suggest_pkgs_from_missing_files(missing_paths: Iterable[str]) -> List[str]:
    return sorted({rpm for p in missing_paths for hint,rpm in PATH_HINTS_TO_RPM.items() if p.startswith(hint)})
def suggest_pkgs_from_missing_sos(missing_paths: Iterable[str]) -> List[str]:
    return sorted({rpm for p in missing_paths for key,rpm in SO_LIB_TO_RPM.items() if os.path.basename(p).startswith(key)})
import re
_LDD_NOTFOUND_RE = re.compile(r'^\s*([^\s]+)\s*=>\s*not found\s*$', re.MULTILINE)
def suggest_pkgs_from_ldd(ldd_text: Optional[str]) -> List[str]:
    if not ldd_text: return []
    return sorted({rpm for m in _LDD_NOTFOUND_RE.finditer(ldd_text)
                   for key,rpm in SO_LIB_TO_RPM.items() if m.group(1).startswith(key)})
def aggregate_runtime_packages_from_probe(probe_result: Dict) -> List[str]:
    miss = {p for b in probe_result.get("bins", []) for p in b.get("files_missing", [])}
    pkgs = set(suggest_pkgs_from_missing_files(miss)) | set(suggest_pkgs_from_missing_sos(miss))
    pkgs.add("ca-certificates")
    return sorted(pkgs)
